#include "Cylinder.h"

#include <cmath>

int Cylinder::SLICES = 32;

Cylinder::Cylinder():
		m_dimensions(0.5f, 1.0f, 1.0f)
{
	init();
}

Cylinder::Cylinder(const Vertex& dim):
		m_dimensions(dim)
{
	init();
}

Cylinder::Cylinder(float top, float bottom, float height):
		m_dimensions(top, bottom, height)
{
	init();
}

Cylinder::Cylinder(const Vertex& dim, const Vertex& pos):
		Assembly(pos), m_dimensions(dim)
{
	init();
}

Cylinder::Cylinder(float top, float bottom, float height, float x, float y, float z):
		Assembly(x, y, z), m_dimensions(top, bottom, height)
{
	init();
}

Cylinder::Cylinder(const Vertex& dim, const Vertex& pos, const Vertex& rot):
		Assembly(pos, rot), m_dimensions(dim)
{
	init();
}

Cylinder::Cylinder(float top, float bottom, float height, float x, float y, float z, float a, float b, float g):
		Assembly(x, y, z, a, b, g), m_dimensions(top, bottom, height)
{
	init();
}


Cylinder::~Cylinder()
{
	for (int t = 0; t < 2; ++t)
	{
		for (int s = 0; s < SLICES; ++s)
		{
			delete m_vertex[t][s];
		}
	}
	
	for (int s = 0; s < SLICES+2; ++s)
	{
		delete m_normal[s];
	}
}


const Vertex& Cylinder::dimensions() const
{
	return m_dimensions;
}

Vertex& Cylinder::dimensions()
{
	m_v_mod = true;
	return m_dimensions;
}

void Cylinder::update_vertex()
{
	float t, b, h;
	m_dimensions.getAll(t, b, h);
	h /= 2.0f;
	
	for (int s = 0; s < SLICES; ++s)
	{
		float angle = 2 * M_PI * static_cast<float>(s) / SLICES;
		float cs = cos(angle), ss = sin(angle);
		
		m_vertex[0][s]->setAll(t * ss,  h, t * cs);
		m_vertex[1][s]->setAll(b * ss, -h, b * cs);
		
		Vertex A(*m_vertex[0][s]), B(*m_vertex[1][s]), AB(B-A);
		if (t < b)
		{
			Vertex C(A);
			C.setY(B.getY());
			*m_normal[s] = (AB^(AB^(C-A))).normalize();
			
		}
		else if (b-t > 0.001f)
		{
			Vertex C(B);
			C.setY(A.getY());
			*m_normal[s] = AB^(AB^(C-A)).normalize();
		}
		else
		{
			Vertex C(0.0f, h, 0.0f);
			*m_normal[s] = (A-C).normalize();
		}
	}
	
	Assembly::update_vertex();
}

void Cylinder::init()
{
	m_name = "cylinder";
	m_vertex.resize(2);
	for (int t = 0; t < 2; ++t)
	{
		m_vertex[t].resize(SLICES);
		for (int s = 0; s < SLICES; ++s)
		{
			m_vertex[t][s] = new Vertex;
		}
	}
	
	// 2 normals more: top + bottom
	m_normal.resize(SLICES+2);
	m_normal[SLICES] = new Vertex(0.0f, 1.0f, 0.0f, 0.0f);
	m_normal[SLICES+1] = new Vertex(0.0f, -1.0f, 0.0f, 0.0f);
	
	for (int s = 0; s < SLICES; ++s)
	{
		m_normal[s] = new Vertex(0.0f, 0.0f, 0.0f, 0.0f);
	}
	
	Face *face_top = new Face(true), *face_bottom = new Face(true);
	for (int s = 0; s < SLICES; ++s)
	{
		int si = (s+1) % SLICES;
		
		const Vertex* const& vt = m_vertex[0][s];
		const Vertex* const& vb = m_vertex[1][s];
		
		face_top->push_back(vt, m_normal[SLICES]);
		face_bottom->push_front(vb, m_normal[SLICES+1]);
		
		Face* face_mid = new Face(false);
		face_mid->push_back(vt, m_normal[s]);
		face_mid->push_back(vb, m_normal[s]);
		face_mid->push_back(m_vertex[1][si], m_normal[si]);
		face_mid->push_back(m_vertex[0][si], m_normal[si]);
		m_face.push_back(face_mid);
	}
	
	m_face.push_back(face_top);
	m_face.push_back(face_bottom);
}

